package com.jenkins.test.proxy.doscan;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.Set;

/**
 * @version V0.0.1
 * @ClassName: {@link AnnotationScanner}
 * @Description: AnnotationScanner
 * @author: Lanzhou
 * @date: 2022/1/23 16:49
 * @Copyright:2019 All rights reserved.
 * 注意：本内容仅限于本人开发与维护，禁止外泄以及用于其他的商业目
 */
public class AnnotationScanner extends ClassPathBeanDefinitionScanner {

    public AnnotationScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * 扫描过滤器, 定义扫描的过滤规则
     */
    @Override
    protected void registerDefaultFilters() {
        // 这个过滤器是默认类扫描器 (不论接口/类/注解(这个玩意就很奇怪了, 试了确实可以)等都会注入)
//        this.addIncludeFilter((metadataReader, metadataReaderFactory) -> true);

        // 扫描规则 - 只扫描我们带有 @Reference 注解的接口
        this.addIncludeFilter(new AnnotationTypeFilter(Reference.class));
    }

    /**
     * 判断注解Bean的定义信息是否是接口和有被依赖使用(未被注入则不初始化当前Bean, 只能, 棒!!!)
     *
     * @param beanDefinition 注解信息
     * @return 是否满足候选组件
     */
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }

    /**
     * 这里不会扫描到真正的实体类
     *
     * @param basePackages 基础包路径
     * @return Bean定义信息, 可以用这里来控制我们Bean信息的代理值
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
            // BeanFactory.getBean的方法跟进去后有一个判断是不是 FactoryBean 类型的。如果是从 FactoryBean.getObject获取
            // ReferenceAnnotationFactoryBean 实现了FactoryBean
            definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
            // FactoryBean是一种特殊的Bean，这里的BeanClass是生成Bean实例的工厂，不是Bean本身。其返回的是该工厂Bean的getObject方法所返回的对象。
            definition.setBeanClass(ReferenceAnnotationFactoryBean.class);
            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
        }
        return beanDefinitions;
    }

}
